package com.sunricher.telinkblemeshlib;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.clj.fastble.BleManager;
import com.sunricher.telinkblemeshlib.models.NaturalLight;

import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NaturalLightManager {

    public static final String LOG_TAG = "NaturalLightManager";

    public static abstract class Callback {

        public abstract void naturalLightManagerDidGetInvalidData(NaturalLightManager manager, int address, NaturalLight.Mode mode);

        public abstract void naturalLightManagerDidGetItem(NaturalLightManager manager, int address, NaturalLight.Item item, NaturalLight.Mode mode);

        public abstract void naturalLightManagerDidResetOK(NaturalLightManager manager, int address);

        public abstract void naturalLightManagerDidSetEnd(NaturalLightManager manager, int address);

        public abstract void naturalLightManagerDidGetEnd(NaturalLightManager manager, int address);

        public abstract void naturalLightManagerDidStateEnabled(NaturalLightManager manager, int address, NaturalLight.Mode mode);

        public abstract void naturalLightManagerDidStateDisabled(NaturalLightManager manager, int address);
    }

    public static abstract class StateCallback {
    }

    private Callback callback;
    private boolean isGettingState;
    private boolean isGettingNatural = false;
    private boolean isSettingNatural = false;
    private final ExecutorService executorService = Executors.newSingleThreadExecutor();
    private Handler uiHandler = new Handler(Looper.getMainLooper());

    public Callback getCallback() {
        return callback;
    }

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    public static NaturalLightManager getInstance() {
        return SingleHolder.instance;
    }

    private static class SingleHolder {
        private static NaturalLightManager instance = new NaturalLightManager();
    }

    private NaturalLightManager() {

    }

    public void getCurrentState(int address) {
        isGettingState = true;
        MeshCommand cmd = MeshCommand.getNaturalLightCurrentState(address);
        MeshManager.getInstance().send(cmd);
    }

    public void startGetNaturalLight(int address, NaturalLight.Mode mode) {
        isGettingNatural = true;
        executorService.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ArrayList<MeshCommand> commands = new ArrayList<>();
            for (int i = 0; i <= 23; i++) {
                MeshCommand cmd = MeshCommand.getNaturalLight(address, mode, i);
                commands.add(cmd);
            }
            while (this.isGettingNatural && commands.size() > 0) {
                MeshCommand command = commands.remove(0);
                MeshManager.getInstance().send(command);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (this.isGettingNatural) {
                if (callback != null) {
                    uiHandler.post(() -> {
                        callback.naturalLightManagerDidGetEnd(this, address);
                    });
                }
            }
        });
    }

    public void stopGetNaturalLight() {
        isGettingNatural = false;
    }

    public void startSetNaturalLight(int address, NaturalLight naturalLight, NaturalLight.Mode mode, boolean isEnabled) {
        isSettingNatural = true;
        executorService.execute(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            MeshCommand disableCmd = MeshCommand.disableNaturalLight(address);
            MeshManager.getInstance().send(disableCmd);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ArrayList<MeshCommand> commands = MeshCommand.setNaturalLight(address, naturalLight, mode);
            while (this.isSettingNatural && commands.size() > 0) {
                MeshCommand command = commands.remove(0);
                MeshManager.getInstance().send(command);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            if (isEnabled) {
                try {
                    Thread.sleep(2000);
                    MeshCommand enableCmd = MeshCommand.enableNaturalLight(address, mode);
                    MeshManager.getInstance().send(enableCmd);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    public void stopSetNaturalLight() {
        isSettingNatural = false;
    }

    void handleCommand(MeshCommand command) {
        int cmd = (int) command.getUserData()[0] & 0xFF;
        if (cmd < 0x60 || cmd > 0x63) {
            // Available cmds are 0x60, 0x61, 0x62, 0x63
            return;
        }
        if (isGettingState) {
            isGettingState = false;
            if (callback != null) {
                uiHandler.post(() -> {
                    int modeRaw = (int) command.getUserData()[1] & 0xFF;
                    if (modeRaw == 0xFF) {
                        callback.naturalLightManagerDidStateDisabled(this, command.getSrc());
                    } else {
                        NaturalLight.Mode mode = NaturalLight.getMode(modeRaw + 1);
                        callback.naturalLightManagerDidStateEnabled(this, command.getSrc(), mode);
                    }
                });
            }
            return;
        }
        int modeRaw = cmd - 0x5F;
        NaturalLight.Mode mode = NaturalLight.getMode(modeRaw);

        int cmd1 = (int) command.getUserData()[1] & 0xFF;
        if (cmd1 <= 23) {
            int hour = cmd1;
            // let minute = 0 // minute always 0
            int brightness = (int) command.getUserData()[3] & 0xFF;
            // let red = command.userData[4]
            // let green = command.userData[5]
            // let blue = command.userData[6]
            int whiteOrCt = (int) command.getUserData()[7] & 0xFF;
            // let isCtEnabled = command.userData[8] == 0x00
            NaturalLight.Item item = new NaturalLight.Item();
            item.setHour(hour);
            // item.minute = minute
            item.setBrightness(brightness);
            item.setCct(whiteOrCt);
            if (callback != null) {
                uiHandler.post(() -> {
                    callback.naturalLightManagerDidGetItem(this, command.getSrc(), item, mode);
                });
            }
            return;
        }
        switch (cmd1) {
            case 0xA0:
                Log.i(LOG_TAG, "didGetEnableResponse natural light");
                break;

            case 0xB0:
                Log.i(LOG_TAG, "didGetDisableResponse natural light");
                break;

            case 0xC0:
                Log.i(LOG_TAG, "didResetResponse natural light");
                if (callback != null) {
                    uiHandler.post(() -> {
                        callback.naturalLightManagerDidResetOK(this, command.getSrc());
                    });
                }
                break;

            case 0x80:
                if (callback != null) {
                    uiHandler.post(() -> {
                        callback.naturalLightManagerDidSetEnd(this, command.getSrc());
                    });
                }
                break;

            case 0xFF:
                // Invalid data
                if (this.isGettingNatural) {
                    stopGetNaturalLight();
                }
                if (callback != null) {
                    uiHandler.post(() -> {
                        callback.naturalLightManagerDidGetInvalidData(this, command.getSrc(), mode);
                    });
                }
                break;

            default:
                break;
        }
    }
}
